home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / network / file-tra / ftp-rl.taz / ftp-rl / ftp / cmds.c next >
Encoding:
C/C++ Source or Header  |  1992-10-07  |  40.1 KB  |  2,250 lines

  1. /*
  2.  * Copyright (c) 1985, 1989 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms are permitted
  6.  * provided that: (1) source distributions retain this entire copyright
  7.  * notice and comment, and (2) distributions including binaries display
  8.  * the following acknowledgement:  ``This product includes software
  9.  * developed by the University of California, Berkeley and its contributors''
  10.  * in the documentation or other materials provided with the distribution
  11.  * and in all advertising materials mentioning features or use of this
  12.  * software. Neither the name of the University nor the names of its
  13.  * contributors may be used to endorse or promote products derived
  14.  * from this software without specific prior written permission.
  15.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  16.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  17.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  18.  */
  19.  
  20. #ifndef lint
  21. static char sccsid[] = "@(#)cmds.c    5.23 (Berkeley) 6/1/90";
  22. #endif /* not lint */
  23.  
  24. /*
  25.  * FTP User Program -- Command Routines.
  26.  */
  27. #include <sys/param.h>
  28. #include <sys/wait.h>
  29. #include <sys/stat.h>
  30. #include <sys/socket.h>
  31.  
  32. #include <arpa/ftp.h>
  33.  
  34. #include <signal.h>
  35. #include <stdio.h>
  36. #include <errno.h>
  37. #include <netdb.h>
  38. #include <ctype.h>
  39. #include <time.h>
  40. #include <netinet/in.h>
  41.  
  42. #include "ftp_var.h"
  43. #include "pathnames.h"
  44.  
  45. extern    char *globerr;
  46. extern    char **glob();
  47. extern    char *home;
  48. extern    char *remglob();
  49. extern    char *getenv();
  50. extern    char *index();
  51. extern    char *rindex();
  52. extern    char *strerror();
  53. extern    int  errno;
  54. extern off_t restart_point;
  55. extern char reply_string[];
  56.  
  57. char *mname;
  58. jmp_buf jabort;
  59. char *dotrans(), *domap();
  60.  
  61. /*
  62.  * Connect to peer server and
  63.  * auto-login, if possible.
  64.  */
  65. setpeer(argc, argv)
  66.     int argc;
  67.     char *argv[];
  68. {
  69.     char *host, *hookup();
  70.     short port;
  71.  
  72.     if (connected) {
  73.         printf("Already connected to %s, use close first.\n",
  74.             hostname);
  75.         code = -1;
  76.         return;
  77.     }
  78.     if (argc < 2) {
  79.         (void) strcat(line, " ");
  80.         printf("(to) ");
  81.         (void) gets(&line[strlen(line)]);
  82.         makeargv();
  83.         argc = margc;
  84.         argv = margv;
  85.     }
  86.     if (argc > 3) {
  87.         printf("usage: %s host-name [port]\n", argv[0]);
  88.         code = -1;
  89.         return;
  90.     }
  91.     port = sp->s_port;
  92.     if (argc > 2) {
  93.         port = atoi(argv[2]);
  94.         if (port <= 0) {
  95.             printf("%s: bad port number-- %s\n", argv[1], argv[2]);
  96.             printf ("usage: %s host-name [port]\n", argv[0]);
  97.             code = -1;
  98.             return;
  99.         }
  100.         port = htons(port);
  101.     }
  102.     host = hookup(argv[1], port);
  103.     if (host) {
  104.         int overbose;
  105.  
  106.         connected = 1;
  107.         /*
  108.          * Set up defaults for FTP.
  109.          */
  110.         (void) strcpy(typename, "ascii"), type = TYPE_A;
  111.         curtype = TYPE_A;
  112.         (void) strcpy(formname, "non-print"), form = FORM_N;
  113.         (void) strcpy(modename, "stream"), mode = MODE_S;
  114.         (void) strcpy(structname, "file"), stru = STRU_F;
  115.         (void) strcpy(bytename, "8"), bytesize = 8;
  116.         if (autologin)
  117.             (void) login(argv[1]);
  118.  
  119. #if defined(unix) && NBBY == 8
  120. /*
  121.  * this ifdef is to keep someone form "porting" this to an incompatible
  122.  * system and not checking this out. This way they have to think about it.
  123.  */
  124.         overbose = verbose;
  125.         if (debug == 0)
  126.             verbose = -1;
  127.         if (command("SYST") == COMPLETE && overbose) {
  128.             register char *cp, c;
  129.             cp = index(reply_string+4, ' ');
  130.             if (cp == NULL)
  131.                 cp = index(reply_string+4, '\r');
  132.             if (cp) {
  133.                 if (cp[-1] == '.')
  134.                     cp--;
  135.                 c = *cp;
  136.                 *cp = '\0';
  137.             }
  138.  
  139.             printf("Remote system type is %s.\n",
  140.                 reply_string+4);
  141.             if (cp)
  142.                 *cp = c;
  143.         }
  144.         if (!strncmp(reply_string, "215 UNIX Type: L8", 17)) {
  145.             if (proxy)
  146.                 unix_proxy = 1;
  147.             else
  148.                 unix_server = 1;
  149.             /*
  150.              * Set type to 0 (not specified by user),
  151.              * meaning binary by default, but don't bother
  152.              * telling server.  We can use binary
  153.              * for text files unless changed by the user.
  154.              */
  155.             type = 0;
  156.             (void) strcpy(typename, "binary");
  157.             if (overbose)
  158.                 printf("Using %s mode to transfer files.\n",
  159.                 typename);
  160.         } else {
  161.             if (proxy)
  162.                 unix_proxy = 0;
  163.             else
  164.                 unix_server = 0;
  165.             if (overbose && 
  166.                 !strncmp(reply_string, "215 TOPS20", 10))
  167.                 printf(
  168. "Remember to set tenex mode when transfering binary files from this machine.\n");
  169.         }
  170.         verbose = overbose;
  171. #endif /* unix */
  172.     }
  173. }
  174.  
  175. struct    types {
  176.     char    *t_name;
  177.     char    *t_mode;
  178.     int    t_type;
  179.     char    *t_arg;
  180. } types[] = {
  181.     { "ascii",    "A",    TYPE_A,    0 },
  182.     { "binary",    "I",    TYPE_I,    0 },
  183.     { "image",    "I",    TYPE_I,    0 },
  184.     { "ebcdic",    "E",    TYPE_E,    0 },
  185.     { "tenex",    "L",    TYPE_L,    bytename },
  186.     0
  187. };
  188.  
  189. /*
  190.  * Set transfer type.
  191.  */
  192. settype(argc, argv)
  193.     char *argv[];
  194. {
  195.     register struct types *p;
  196.     int comret;
  197.  
  198.     if (argc > 2) {
  199.         char *sep;
  200.  
  201.         printf("usage: %s [", argv[0]);
  202.         sep = " ";
  203.         for (p = types; p->t_name; p++) {
  204.             printf("%s%s", sep, p->t_name);
  205.             sep = " | ";
  206.         }
  207.         printf(" ]\n");
  208.         code = -1;
  209.         return;
  210.     }
  211.     if (argc < 2) {
  212.         printf("Using %s mode to transfer files.\n", typename);
  213.         code = 0;
  214.         return;
  215.     }
  216.     for (p = types; p->t_name; p++)
  217.         if (strcmp(argv[1], p->t_name) == 0)
  218.             break;
  219.     if (p->t_name == 0) {
  220.         printf("%s: unknown mode\n", argv[1]);
  221.         code = -1;
  222.         return;
  223.     }
  224.     if ((p->t_arg != NULL) && (*(p->t_arg) != '\0'))
  225.         comret = command ("TYPE %s %s", p->t_mode, p->t_arg);
  226.     else
  227.         comret = command("TYPE %s", p->t_mode);
  228.     if (comret == COMPLETE) {
  229.         (void) strcpy(typename, p->t_name);
  230.         curtype = type = p->t_type;
  231.     }
  232. }
  233.  
  234. /*
  235.  * Internal form of settype; changes current type in use with server
  236.  * without changing our notion of the type for data transfers.
  237.  * Used to change to and from ascii for listings.
  238.  */
  239. changetype(newtype, show)
  240.     int newtype, show;
  241. {
  242.     register struct types *p;
  243.     int comret, oldverbose = verbose;
  244.  
  245.     if (newtype == 0)
  246.         newtype = TYPE_I;
  247.     if (newtype == curtype)
  248.         return;
  249.     if (debug == 0 && show == 0)
  250.         verbose = 0;
  251.     for (p = types; p->t_name; p++)
  252.         if (newtype == p->t_type)
  253.             break;
  254.     if (p->t_name == 0) {
  255.         printf("ftp: internal error: unknown type %d\n", newtype);
  256.         return;
  257.     }
  258.     if (newtype == TYPE_L && bytename[0] != '\0')
  259.         comret = command("TYPE %s %s", p->t_mode, bytename);
  260.     else
  261.         comret = command("TYPE %s", p->t_mode);
  262.     if (comret == COMPLETE)
  263.         curtype = newtype;
  264.     verbose = oldverbose;
  265. }
  266.  
  267. char *stype[] = {
  268.     "type",
  269.     "",
  270.     0
  271. };
  272.  
  273. /*
  274.  * Set binary transfer type.
  275.  */
  276. /*VARARGS*/
  277. setbinary()
  278. {
  279.     stype[1] = "binary";
  280.     settype(2, stype);
  281. }
  282.  
  283. /*
  284.  * Set ascii transfer type.
  285.  */
  286. /*VARARGS*/
  287. setascii()
  288. {
  289.     stype[1] = "ascii";
  290.     settype(2, stype);
  291. }
  292.  
  293. /*
  294.  * Set tenex transfer type.
  295.  */
  296. /*VARARGS*/
  297. settenex()
  298. {
  299.     stype[1] = "tenex";
  300.     settype(2, stype);
  301. }
  302.  
  303. /*
  304.  * Set file transfer mode.
  305.  */
  306. /*ARGSUSED*/
  307. setmode(argc, argv)
  308.     char *argv[];
  309. {
  310.  
  311.     printf("We only support %s mode, sorry.\n", modename);
  312.     code = -1;
  313. }
  314.  
  315. /*
  316.  * Set file transfer format.
  317.  */
  318. /*ARGSUSED*/
  319. setform(argc, argv)
  320.     char *argv[];
  321. {
  322.  
  323.     printf("We only support %s format, sorry.\n", formname);
  324.     code = -1;
  325. }
  326.  
  327. /*
  328.  * Set file transfer structure.
  329.  */
  330. /*ARGSUSED*/
  331. setstruct(argc, argv)
  332.     char *argv[];
  333. {
  334.  
  335.     printf("We only support %s structure, sorry.\n", structname);
  336.     code = -1;
  337. }
  338.  
  339. /*
  340.  * Send a single file.
  341.  */
  342. put(argc, argv)
  343.     int argc;
  344.     char *argv[];
  345. {
  346.     char *cmd;
  347.     int loc = 0;
  348.     char *oldargv1, *oldargv2;
  349.  
  350.     if (argc == 2) {
  351.         argc++;
  352.         argv[2] = argv[1];
  353.         loc++;
  354.     }
  355.     if (argc < 2) {
  356.         (void) strcat(line, " ");
  357.         printf("(local-file) ");
  358.         (void) gets(&line[strlen(line)]);
  359.         makeargv();
  360.         argc = margc;
  361.         argv = margv;
  362.     }
  363.     if (argc < 2) {
  364. usage:
  365.         printf("usage:%s local-file remote-file\n", argv[0]);
  366.         code = -1;
  367.         return;
  368.     }
  369.     if (argc < 3) {
  370.         (void) strcat(line, " ");
  371.         printf("(remote-file) ");
  372.         (void) gets(&line[strlen(line)]);
  373.         makeargv();
  374.         argc = margc;
  375.         argv = margv;
  376.     }
  377.     if (argc < 3) 
  378.         goto usage;
  379.     oldargv1 = argv[1];
  380.     oldargv2 = argv[2];
  381.     if (!globulize(&argv[1])) {
  382.         code = -1;
  383.         return;
  384.     }
  385.     /*
  386.      * If "globulize" modifies argv[1], and argv[2] is a copy of
  387.      * the old argv[1], make it a copy of the new argv[1].
  388.      */
  389.     if (argv[1] != oldargv1 && argv[2] == oldargv1) {
  390.         argv[2] = argv[1];
  391.     }
  392.     cmd = (argv[0][0] == 'a') ? "APPE" : ((sunique) ? "STOU" : "STOR");
  393.     if (loc && ntflag) {
  394.         argv[2] = dotrans(argv[2]);
  395.     }
  396.     if (loc && mapflag) {
  397.         argv[2] = domap(argv[2]);
  398.     }
  399.     sendrequest(cmd, argv[1], argv[2],
  400.         argv[1] != oldargv1 || argv[2] != oldargv2);
  401. }
  402.  
  403. /*
  404.  * Send multiple files.
  405.  */
  406. mput(argc, argv)
  407.     int argc;
  408.     char **argv;
  409. {
  410.     extern jmp_buf jabort;
  411.     register int i;
  412.     sig_t oldintr;
  413.     int ointer;
  414.     char *tp;
  415.     void mabort();
  416.  
  417.     if (argc < 2) {
  418.         (void) strcat(line, " ");
  419.         printf("(local-files) ");
  420.         (void) gets(&line[strlen(line)]);
  421.         makeargv();
  422.         argc = margc;
  423.         argv = margv;
  424.     }
  425.     if (argc < 2) {
  426.         printf("usage:%s local-files\n", argv[0]);
  427.         code = -1;
  428.         return;
  429.     }
  430.     mname = argv[0];
  431.     mflag = 1;
  432.     oldintr = signal(SIGINT, mabort);
  433.     (void) setjmp(jabort);
  434.     if (proxy) {
  435.         char *cp, *tp2, tmpbuf[MAXPATHLEN];
  436.  
  437.         while ((cp = remglob(argv,0)) != NULL) {
  438.             if (*cp == 0) {
  439.                 mflag = 0;
  440.                 continue;
  441.             }
  442.             if (mflag && confirm(argv[0], cp)) {
  443.                 tp = cp;
  444.                 if (mcase) {
  445.                     while (*tp && !islower(*tp)) {
  446.                         tp++;
  447.                     }
  448.                     if (!*tp) {
  449.                         tp = cp;
  450.                         tp2 = tmpbuf;
  451.                         while ((*tp2 = *tp) != NULL) {
  452.                              if (isupper(*tp2)) {
  453.                                 *tp2 = 'a' + *tp2 - 'A';
  454.                              }
  455.                              tp++;
  456.                              tp2++;
  457.                         }
  458.                     }
  459.                     tp = tmpbuf;
  460.                 }
  461.                 if (ntflag) {
  462.                     tp = dotrans(tp);
  463.                 }
  464.                 if (mapflag) {
  465.                     tp = domap(tp);
  466.                 }
  467.                 sendrequest((sunique) ? "STOU" : "STOR",
  468.                     cp, tp, cp != tp || !interactive);
  469.                 if (!mflag && fromatty) {
  470.                     ointer = interactive;
  471.                     interactive = 1;
  472.                     if (confirm("Continue with","mput")) {
  473.                         mflag++;
  474.                     }
  475.                     interactive = ointer;
  476.                 }
  477.             }
  478.         }
  479.         (void) signal(SIGINT, oldintr);
  480.         mflag = 0;
  481.         return;
  482.     }
  483.     for (i = 1; i < argc; i++) {
  484.         register char **cpp, **gargs;
  485.  
  486.         if (!doglob) {
  487.             if (mflag && confirm(argv[0], argv[i])) {
  488.                 tp = (ntflag) ? dotrans(argv[i]) : argv[i];
  489.                 tp = (mapflag) ? domap(tp) : tp;
  490.                 sendrequest((sunique) ? "STOU" : "STOR",
  491.                     argv[i], tp, tp != argv[i] || !interactive);
  492.                 if (!mflag && fromatty) {
  493.                     ointer = interactive;
  494.                     interactive = 1;
  495.                     if (confirm("Continue with","mput")) {
  496.                         mflag++;
  497.                     }
  498.                     interactive = ointer;
  499.                 }
  500.             }
  501.             continue;
  502.         }
  503.         gargs = glob(argv[i]);
  504.         if (globerr != NULL) {
  505.             printf("%s\n", globerr);
  506.             if (gargs) {
  507.                 blkfree(gargs);
  508.                 free((char *)gargs);
  509.             }
  510.             continue;
  511.         }
  512.         for (cpp = gargs; cpp && *cpp != NULL; cpp++) {
  513.             if (mflag && confirm(argv[0], *cpp)) {
  514.                 tp = (ntflag) ? dotrans(*cpp) : *cpp;
  515.                 tp = (mapflag) ? domap(tp) : tp;
  516.                 sendrequest((sunique) ? "STOU" : "STOR",
  517.                     *cpp, tp, *cpp != tp || !interactive);
  518.                 if (!mflag && fromatty) {
  519.                     ointer = interactive;
  520.                     interactive = 1;
  521.                     if (confirm("Continue with","mput")) {
  522.                         mflag++;
  523.                     }
  524.                     interactive = ointer;
  525.                 }
  526.             }
  527.         }
  528.         if (gargs != NULL) {
  529.             blkfree(gargs);
  530.             free((char *)gargs);
  531.         }
  532.     }
  533.     (void) signal(SIGINT, oldintr);
  534.     mflag = 0;
  535. }
  536.  
  537. reget(argc, argv)
  538.     char *argv[];
  539. {
  540.     (void) getit(argc, argv, 1, "r+w");
  541. }
  542.  
  543. get(argc, argv)
  544.     char *argv[];
  545. {
  546.     (void) getit(argc, argv, 0, restart_point ? "r+w" : "w" );
  547. }
  548.  
  549. /*
  550.  * Receive one file.
  551.  */
  552. getit(argc, argv, restartit, mode)
  553.     char *argv[];
  554.     char *mode;
  555. {
  556.     int loc = 0;
  557.     char *oldargv1, *oldargv2;
  558.  
  559.     if (argc == 2) {
  560.         argc++;
  561.         argv[2] = argv[1];
  562.         loc++;
  563.     }
  564.     if (argc < 2) {
  565.         (void) strcat(line, " ");
  566.         printf("(remote-file) ");
  567.         (void) gets(&line[strlen(line)]);
  568.         makeargv();
  569.         argc = margc;
  570.         argv = margv;
  571.     }
  572.     if (argc < 2) {
  573. usage:
  574.         printf("usage: %s remote-file [ local-file ]\n", argv[0]);
  575.         code = -1;
  576.         return (0);
  577.     }
  578.     if (argc < 3) {
  579.         (void) strcat(line, " ");
  580.         printf("(local-file) ");
  581.         (void) gets(&line[strlen(line)]);
  582.         makeargv();
  583.         argc = margc;
  584.         argv = margv;
  585.     }
  586.     if (argc < 3) 
  587.         goto usage;
  588.     oldargv1 = argv[1];
  589.     oldargv2 = argv[2];
  590.     if (!globulize(&argv[2])) {
  591.         code = -1;
  592.         return (0);
  593.     }
  594.     if (loc && mcase) {
  595.         char *tp = argv[1], *tp2, tmpbuf[MAXPATHLEN];
  596.  
  597.         while (*tp && !islower(*tp)) {
  598.             tp++;
  599.         }
  600.         if (!*tp) {
  601.             tp = argv[2];
  602.             tp2 = tmpbuf;
  603.             while ((*tp2 = *tp) != NULL) {
  604.                 if (isupper(*tp2)) {
  605.                     *tp2 = 'a' + *tp2 - 'A';
  606.                 }
  607.                 tp++;
  608.                 tp2++;
  609.             }
  610.             argv[2] = tmpbuf;
  611.         }
  612.     }
  613.     if (loc && ntflag)
  614.         argv[2] = dotrans(argv[2]);
  615.     if (loc && mapflag)
  616.         argv[2] = domap(argv[2]);
  617.     if (restartit) {
  618.         struct stat stbuf;
  619.         int ret;
  620.  
  621.         ret = stat(argv[2], &stbuf);
  622.         if (restartit == 1) {
  623.             if (ret < 0) {
  624.                 fprintf(stderr, "local: %s: %s\n", argv[2],
  625.                     strerror(errno));
  626.                 return (0);
  627.             }
  628.             restart_point = stbuf.st_size;
  629.         } else {
  630.             if (ret == 0) {
  631.                 int overbose;
  632.  
  633.                 overbose = verbose;
  634.                 if (debug == 0)
  635.                     verbose = -1;
  636.                 if (command("MDTM %s", argv[1]) == COMPLETE) {
  637.                     int yy, mo, day, hour, min, sec;
  638.                     struct tm *tm;
  639.                     verbose = overbose;
  640.                     sscanf(reply_string,
  641.                         "%*s %04d%02d%02d%02d%02d%02d",
  642.                         &yy, &mo, &day, &hour, &min, &sec);
  643.                     tm = gmtime(&stbuf.st_mtime);
  644.                     tm->tm_mon++;
  645.                     if (tm->tm_year > yy%100)
  646.                         return (1);
  647.                     else if (tm->tm_year == yy%100) {
  648.                         if (tm->tm_mon > mo)
  649.                             return (1);
  650.                     } else if (tm->tm_mon == mo) {
  651.                         if (tm->tm_mday > day)
  652.                             return (1);
  653.                     } else if (tm->tm_mday == day) {
  654.                         if (tm->tm_hour > hour)
  655.                             return (1);
  656.                     } else if (tm->tm_hour == hour) {
  657.                         if (tm->tm_min > min)
  658.                             return (1);
  659.                     } else if (tm->tm_min == min) {
  660.                         if (tm->tm_sec > sec)
  661.                             return (1);
  662.                     }
  663.                 } else {
  664.                     printf("%s\n", reply_string);
  665.                     verbose = overbose;
  666.                     return (0);
  667.                 }
  668.             }
  669.         }
  670.     }
  671.  
  672.     recvrequest("RETR", argv[2], argv[1], mode,
  673.         argv[1] != oldargv1 || argv[2] != oldargv2);
  674.     restart_point = 0;
  675.     return (0);
  676. }
  677.  
  678. void
  679. mabort()
  680. {
  681.     int ointer;
  682.     extern jmp_buf jabort;
  683.  
  684.     printf("\n");
  685.     (void) fflush(stdout);
  686.     if (mflag && fromatty) {
  687.         ointer = interactive;
  688.         interactive = 1;
  689.         if (confirm("Continue with", mname)) {
  690.             interactive = ointer;
  691.             longjmp(jabort,0);
  692.         }
  693.         interactive = ointer;
  694.     }
  695.     mflag = 0;
  696.     longjmp(jabort,0);
  697. }
  698.  
  699. /*
  700.  * Get multiple files.
  701.  */
  702. mget(argc, argv)
  703.     int argc;
  704.     char **argv;
  705. {
  706.     extern jmp_buf jabort;
  707.     sig_t oldintr;
  708.     int ointer;
  709.     char *cp, *tp, *tp2, tmpbuf[MAXPATHLEN];
  710.     void mabort();
  711.  
  712.     if (argc < 2) {
  713.         (void) strcat(line, " ");
  714.         printf("(remote-files) ");
  715.         (void) gets(&line[strlen(line)]);
  716.         makeargv();
  717.         argc = margc;
  718.         argv = margv;
  719.     }
  720.     if (argc < 2) {
  721.         printf("usage:%s remote-files\n", argv[0]);
  722.         code = -1;
  723.         return;
  724.     }
  725.     mname = argv[0];
  726.     mflag = 1;
  727.     oldintr = signal(SIGINT,mabort);
  728.     (void) setjmp(jabort);
  729.     while ((cp = remglob(argv,proxy)) != NULL) {
  730.         if (*cp == '\0') {
  731.             mflag = 0;
  732.             continue;
  733.         }
  734.         if (mflag && confirm(argv[0], cp)) {
  735.             tp = cp;
  736.             if (mcase) {
  737.                 while (*tp && !islower(*tp)) {
  738.                     tp++;
  739.                 }
  740.                 if (!*tp) {
  741.                     tp = cp;
  742.                     tp2 = tmpbuf;
  743.                     while ((*tp2 = *tp) != NULL) {
  744.                         if (isupper(*tp2)) {
  745.                             *tp2 = 'a' + *tp2 - 'A';
  746.                         }
  747.                         tp++;
  748.                         tp2++;
  749.                     }
  750.                 }
  751.                 tp = tmpbuf;
  752.             }
  753.             if (ntflag) {
  754.                 tp = dotrans(tp);
  755.             }
  756.             if (mapflag) {
  757.                 tp = domap(tp);
  758.             }
  759.             recvrequest("RETR", tp, cp, "w",
  760.                 tp != cp || !interactive);
  761.             if (!mflag && fromatty) {
  762.                 ointer = interactive;
  763.                 interactive = 1;
  764.                 if (confirm("Continue with","mget")) {
  765.                     mflag++;
  766.                 }
  767.                 interactive = ointer;
  768.             }
  769.         }
  770.     }
  771.     (void) signal(SIGINT,oldintr);
  772.     mflag = 0;
  773. }
  774.  
  775. char *
  776. remglob(argv,doswitch)
  777.     char *argv[];
  778.     int doswitch;
  779. {
  780.     char temp[16];
  781.     static char buf[MAXPATHLEN];
  782.     static FILE *ftemp = NULL;
  783.     static char **args;
  784.     int oldverbose, oldhash;
  785.     char *cp, *mode;
  786.  
  787.     if (!mflag) {
  788.         if (!doglob) {
  789.             args = NULL;
  790.         }
  791.         else {
  792.             if (ftemp) {
  793.                 (void) fclose(ftemp);
  794.                 ftemp = NULL;
  795.             }
  796.         }
  797.         return(NULL);
  798.     }
  799.     if (!doglob) {
  800.         if (args == NULL)
  801.             args = argv;
  802.         if ((cp = *++args) == NULL)
  803.             args = NULL;
  804.         return (cp);
  805.     }
  806.     if (ftemp == NULL) {
  807.         (void) strcpy(temp, _PATH_TMP);
  808.         (void) mktemp(temp);
  809.         oldverbose = verbose, verbose = 0;
  810.         oldhash = hash, hash = 0;
  811.         if (doswitch) {
  812.             pswitch(!proxy);
  813.         }
  814.         for (mode = "w"; *++argv != NULL; mode = "a")
  815.             recvrequest ("NLST", temp, *argv, mode, 0);
  816.         if (doswitch) {
  817.             pswitch(!proxy);
  818.         }
  819.         verbose = oldverbose; hash = oldhash;
  820.         ftemp = fopen(temp, "r");
  821.         (void) unlink(temp);
  822.         if (ftemp == NULL) {
  823.             printf("can't find list of remote files, oops\n");
  824.             return (NULL);
  825.         }
  826.     }
  827.     if (fgets(buf, sizeof (buf), ftemp) == NULL) {
  828.         (void) fclose(ftemp), ftemp = NULL;
  829.         return (NULL);
  830.     }
  831.     if ((cp = index(buf, '\n')) != NULL)
  832.         *cp = '\0';
  833.     return (buf);
  834. }
  835.  
  836. char *
  837. onoff(bool)
  838.     int bool;
  839. {
  840.  
  841.     return (bool ? "on" : "off");
  842. }
  843.  
  844. /*
  845.  * Show status.
  846.  */
  847. /*ARGSUSED*/
  848. status(argc, argv)
  849.     char *argv[];
  850. {
  851.     int i;
  852.  
  853.     if (connected)
  854.         printf("Connected to %s.\n", hostname);
  855.     else
  856.         printf("Not connected.\n");
  857.     if (!proxy) {
  858.         pswitch(1);
  859.         if (connected) {
  860.             printf("Connected for proxy commands to %s.\n", hostname);
  861.         }
  862.         else {
  863.             printf("No proxy connection.\n");
  864.         }
  865.         pswitch(0);
  866.     }
  867.     printf("Mode: %s; Type: %s; Form: %s; Structure: %s\n",
  868.         modename, typename, formname, structname);
  869.     printf("Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s\n", 
  870.         onoff(verbose), onoff(bell), onoff(interactive),
  871.         onoff(doglob));
  872.     printf("Store unique: %s; Receive unique: %s\n", onoff(sunique),
  873.         onoff(runique));
  874.     printf("Case: %s; CR stripping: %s\n",onoff(mcase),onoff(crflag));
  875.     if (ntflag) {
  876.         printf("Ntrans: (in) %s (out) %s\n", ntin,ntout);
  877.     }
  878.     else {
  879.         printf("Ntrans: off\n");
  880.     }
  881.     if (mapflag) {
  882.         printf("Nmap: (in) %s (out) %s\n", mapin, mapout);
  883.     }
  884.     else {
  885.         printf("Nmap: off\n");
  886.     }
  887.     printf("Hash mark printing: %s; Use of PORT cmds: %s\n",
  888.         onoff(hash), onoff(sendport));
  889.     if (macnum > 0) {
  890.         printf("Macros:\n");
  891.         for (i=0; i<macnum; i++) {
  892.             printf("\t%s\n",macros[i].mac_name);
  893.         }
  894.     }
  895.     code = 0;
  896. }
  897.  
  898. /*
  899.  * Set beep on cmd completed mode.
  900.  */
  901. /*VARARGS*/
  902. setbell()
  903. {
  904.  
  905.     bell = !bell;
  906.     printf("Bell mode %s.\n", onoff(bell));
  907.     code = bell;
  908. }
  909.  
  910. /*
  911.  * Turn on packet tracing.
  912.  */
  913. /*VARARGS*/
  914. settrace()
  915. {
  916.  
  917.     trace = !trace;
  918.     printf("Packet tracing %s.\n", onoff(trace));
  919.     code = trace;
  920. }
  921.  
  922. /*
  923.  * Toggle hash mark printing during transfers.
  924.  */
  925. /*VARARGS*/
  926. sethash()
  927. {
  928.  
  929.     hash = !hash;
  930.     printf("Hash mark printing %s", onoff(hash));
  931.     code = hash;
  932.     if (hash)
  933.         printf(" (%d bytes/hash mark)", 1024);
  934.     printf(".\n");
  935. }
  936.  
  937. /*
  938.  * Turn on printing of server echo's.
  939.  */
  940. /*VARARGS*/
  941. setverbose()
  942. {
  943.  
  944.     verbose = !verbose;
  945.     printf("Verbose mode %s.\n", onoff(verbose));
  946.     code = verbose;
  947. }
  948.  
  949. /*
  950.  * Toggle PORT cmd use before each data connection.
  951.  */
  952. /*VARARGS*/
  953. setport()
  954. {
  955.  
  956.     sendport = !sendport;
  957.     printf("Use of PORT cmds %s.\n", onoff(sendport));
  958.     code = sendport;
  959. }
  960.  
  961. /*
  962.  * Turn on interactive prompting
  963.  * during mget, mput, and mdelete.
  964.  */
  965. /*VARARGS*/
  966. setprompt()
  967. {
  968.  
  969.     interactive = !interactive;
  970.     printf("Interactive mode %s.\n", onoff(interactive));
  971.     code = interactive;
  972. }
  973.  
  974. /*
  975.  * Toggle metacharacter interpretation
  976.  * on local file names.
  977.  */
  978. /*VARARGS*/
  979. setglob()
  980. {
  981.     
  982.     doglob = !doglob;
  983.     printf("Globbing %s.\n", onoff(doglob));
  984.     code = doglob;
  985. }
  986.  
  987. /*
  988.  * Set debugging mode on/off and/or
  989.  * set level of debugging.
  990.  */
  991. /*VARARGS*/
  992. setdebug(argc, argv)
  993.     char *argv[];
  994. {
  995.     int val;
  996.  
  997.     if (argc > 1) {
  998.         val = atoi(argv[1]);
  999.         if (val < 0) {
  1000.             printf("%s: bad debugging value.\n", argv[1]);
  1001.             code = -1;
  1002.             return;
  1003.         }
  1004.     } else
  1005.         val = !debug;
  1006.     debug = val;
  1007.     if (debug)
  1008.         options |= SO_DEBUG;
  1009.     else
  1010.         options &= ~SO_DEBUG;
  1011.     printf("Debugging %s (debug=%d).\n", onoff(debug), debug);
  1012.     code = debug > 0;
  1013. }
  1014.  
  1015. /*
  1016.  * Set current working directory
  1017.  * on remote machine.
  1018.  */
  1019. cd(argc, argv)
  1020.     char *argv[];
  1021. {
  1022.  
  1023.     if (argc < 2) {
  1024.         (void) strcat(line, " ");
  1025.         printf("(remote-directory) ");
  1026.         (void) gets(&line[strlen(line)]);
  1027.         makeargv();
  1028.         argc = margc;
  1029.         argv = margv;
  1030.     }
  1031.     if (argc < 2) {
  1032.         printf("usage:%s remote-directory\n", argv[0]);
  1033.         code = -1;
  1034.         return;
  1035.     }
  1036.     if (command("CWD %s", argv[1]) == ERROR && code == 500) {
  1037.         if (verbose)
  1038.             printf("CWD command not recognized, trying XCWD\n");
  1039.         (void) command("XCWD %s", argv[1]);
  1040.     }
  1041. }
  1042.  
  1043. /*
  1044.  * Set current working directory
  1045.  * on local machine.
  1046.  */
  1047. lcd(argc, argv)
  1048.     char *argv[];
  1049. {
  1050.     char buf[MAXPATHLEN];
  1051.     extern char *getwd();
  1052.  
  1053.     if (argc < 2)
  1054.         argc++, argv[1] = home;
  1055.     if (argc != 2) {
  1056.         printf("usage:%s local-directory\n", argv[0]);
  1057.         code = -1;
  1058.         return;
  1059.     }
  1060.     if (!globulize(&argv[1])) {
  1061.         code = -1;
  1062.         return;
  1063.     }
  1064.     if (chdir(argv[1]) < 0) {
  1065.         fprintf(stderr, "local: %s: %s\n", argv[1], strerror(errno));
  1066.         code = -1;
  1067.         return;
  1068.     }
  1069.     printf("Local directory now %s\n", getwd(buf));
  1070.     code = 0;
  1071. }
  1072.  
  1073. /*
  1074.  * Delete a single file.
  1075.  */
  1076. delete(argc, argv)
  1077.     char *argv[];
  1078. {
  1079.  
  1080.     if (argc < 2) {
  1081.         (void) strcat(line, " ");
  1082.         printf("(remote-file) ");
  1083.         (void) gets(&line[strlen(line)]);
  1084.         makeargv();
  1085.         argc = margc;
  1086.         argv = margv;
  1087.     }
  1088.     if (argc < 2) {
  1089.         printf("usage:%s remote-file\n", argv[0]);
  1090.         code = -1;
  1091.         return;
  1092.     }
  1093.     (void) command("DELE %s", argv[1]);
  1094. }
  1095.  
  1096. /*
  1097.  * Delete multiple files.
  1098.  */
  1099. mdelete(argc, argv)
  1100.     int argc;
  1101.     char **argv;
  1102. {
  1103.     extern jmp_buf jabort;
  1104.     sig_t oldintr;
  1105.     int ointer;
  1106.     char *cp;
  1107.     void mabort();
  1108.  
  1109.     if (argc < 2) {
  1110.         (void) strcat(line, " ");
  1111.         printf("(remote-files) ");
  1112.         (void) gets(&line[strlen(line)]);
  1113.         makeargv();
  1114.         argc = margc;
  1115.         argv = margv;
  1116.     }
  1117.     if (argc < 2) {
  1118.         printf("usage:%s remote-files\n", argv[0]);
  1119.         code = -1;
  1120.         return;
  1121.     }
  1122.     mname = argv[0];
  1123.     mflag = 1;
  1124.     oldintr = signal(SIGINT, mabort);
  1125.     (void) setjmp(jabort);
  1126.     while ((cp = remglob(argv,0)) != NULL) {
  1127.         if (*cp == '\0') {
  1128.             mflag = 0;
  1129.             continue;
  1130.         }
  1131.         if (mflag && confirm(argv[0], cp)) {
  1132.             (void) command("DELE %s", cp);
  1133.             if (!mflag && fromatty) {
  1134.                 ointer = interactive;
  1135.                 interactive = 1;
  1136.                 if (confirm("Continue with", "mdelete")) {
  1137.                     mflag++;
  1138.                 }
  1139.                 interactive = ointer;
  1140.             }
  1141.         }
  1142.     }
  1143.     (void) signal(SIGINT, oldintr);
  1144.     mflag = 0;
  1145. }
  1146.  
  1147. /*
  1148.  * Rename a remote file.
  1149.  */
  1150. renamefile(argc, argv)
  1151.     char *argv[];
  1152. {
  1153.  
  1154.     if (argc < 2) {
  1155.         (void) strcat(line, " ");
  1156.         printf("(from-name) ");
  1157.         (void) gets(&line[strlen(line)]);
  1158.         makeargv();
  1159.         argc = margc;
  1160.         argv = margv;
  1161.     }
  1162.     if (argc < 2) {
  1163. usage:
  1164.         printf("%s from-name to-name\n", argv[0]);
  1165.         code = -1;
  1166.         return;
  1167.     }
  1168.     if (argc < 3) {
  1169.         (void) strcat(line, " ");
  1170.         printf("(to-name) ");
  1171.         (void) gets(&line[strlen(line)]);
  1172.         makeargv();
  1173.         argc = margc;
  1174.         argv = margv;
  1175.     }
  1176.     if (argc < 3) 
  1177.         goto usage;
  1178.     if (command("RNFR %s", argv[1]) == CONTINUE)
  1179.         (void) command("RNTO %s", argv[2]);
  1180. }
  1181.  
  1182. /*
  1183.  * Get a directory listing
  1184.  * of remote files.
  1185.  */
  1186. ls(argc, argv)
  1187.     char *argv[];
  1188. {
  1189.     char *cmd;
  1190.  
  1191.     if (argc < 2)
  1192.         argc++, argv[1] = NULL;
  1193.     if (argc < 3)
  1194.         argc++, argv[2] = "-";
  1195.     if (argc > 3) {
  1196.         printf("usage: %s remote-directory local-file\n", argv[0]);
  1197.         code = -1;
  1198.         return;
  1199.     }
  1200.     cmd = argv[0][0] == 'n' ? "NLST" : "LIST";
  1201.     if (strcmp(argv[2], "-") && !globulize(&argv[2])) {
  1202.         code = -1;
  1203.         return;
  1204.     }
  1205.     if (strcmp(argv[2], "-") && *argv[2] != '|')
  1206.         if (!globulize(&argv[2]) || !confirm("output to local-file:", argv[2])) {
  1207.             code = -1;
  1208.             return;
  1209.     }
  1210.     recvrequest(cmd, argv[2], argv[1], "w", 0);
  1211. }
  1212.  
  1213. /*
  1214.  * Get a directory listing
  1215.  * of multiple remote files.
  1216.  */
  1217. mls(argc, argv)
  1218.     int argc;
  1219.     char **argv;
  1220. {
  1221.     extern jmp_buf jabort;
  1222.     sig_t oldintr;
  1223.     int ointer, i;
  1224.     char *cmd, mode[1], *dest;
  1225.     void mabort();
  1226.  
  1227.     if (argc < 2) {
  1228.         (void) strcat(line, " ");
  1229.         printf("(remote-files) ");
  1230.         (void) gets(&line[strlen(line)]);
  1231.         makeargv();
  1232.         argc = margc;
  1233.         argv = margv;
  1234.     }
  1235.     if (argc < 3) {
  1236.         (void) strcat(line, " ");
  1237.         printf("(local-file) ");
  1238.         (void) gets(&line[strlen(line)]);
  1239.         makeargv();
  1240.         argc = margc;
  1241.         argv = margv;
  1242.     }
  1243.     if (argc < 3) {
  1244.         printf("usage:%s remote-files local-file\n", argv[0]);
  1245.         code = -1;
  1246.         return;
  1247.     }
  1248.     dest = argv[argc - 1];
  1249.     argv[argc - 1] = NULL;
  1250.     if (strcmp(dest, "-") && *dest != '|')
  1251.         if (!globulize(&dest) || !confirm("output to local-file:", dest)) {
  1252.             code = -1;
  1253.             return;
  1254.     }
  1255.     cmd = argv[0][1] == 'l' ? "NLST" : "LIST";
  1256.     mname = argv[0];
  1257.     mflag = 1;
  1258.     oldintr = signal(SIGINT, mabort);
  1259.     (void) setjmp(jabort);
  1260.     for (i = 1; mflag && i < argc-1; ++i) {
  1261.         *mode = (i == 1) ? 'w' : 'a';
  1262.         recvrequest(cmd, dest, argv[i], mode, 0);
  1263.         if (!mflag && fromatty) {
  1264.             ointer = interactive;
  1265.             interactive = 1;
  1266.             if (confirm("Continue with", argv[0])) {
  1267.                 mflag ++;
  1268.             }
  1269.             interactive = ointer;
  1270.         }
  1271.     }
  1272.     (void) signal(SIGINT, oldintr);
  1273.     mflag = 0;
  1274. }
  1275.  
  1276. /*
  1277.  * Do a shell escape
  1278.  */
  1279. /*ARGSUSED*/
  1280. shell(argc, argv)
  1281.     int argc;
  1282.     char **argv;
  1283. {
  1284.     int pid;
  1285.     sig_t old1, old2;
  1286.     char shellnam[40], *shell, *namep; 
  1287.     pid_t status;
  1288.  
  1289.     old1 = signal (SIGINT, SIG_IGN);
  1290.     old2 = signal (SIGQUIT, SIG_IGN);
  1291.     if ((pid = fork()) == 0) {
  1292.         for (pid = 3; pid < 20; pid++)
  1293.             (void) close(pid);
  1294.         (void) signal(SIGINT, SIG_DFL);
  1295.         (void) signal(SIGQUIT, SIG_DFL);
  1296.         shell = getenv("SHELL");
  1297.         if (shell == NULL)
  1298.             shell = _PATH_BSHELL;
  1299.         namep = rindex(shell,'/');
  1300.         if (namep == NULL)
  1301.             namep = shell;
  1302.         (void) strcpy(shellnam,"-");
  1303.         (void) strcat(shellnam, ++namep);
  1304.         if (strcmp(namep, "sh") != 0)
  1305.             shellnam[0] = '+';
  1306.         if (debug) {
  1307.             printf ("%s\n", shell);
  1308.             (void) fflush (stdout);
  1309.         }
  1310.         if (argc > 1) {
  1311.             execl(shell,shellnam,"-c",altarg,(char *)0);
  1312.         }
  1313.         else {
  1314.             execl(shell,shellnam,(char *)0);
  1315.         }
  1316.         perror(shell);
  1317.         code = -1;
  1318.         exit(1);
  1319.         }
  1320.     if (pid > 0)
  1321.         while (wait(&status) != pid)
  1322.             ;
  1323.     (void) signal(SIGINT, old1);
  1324.     (void) signal(SIGQUIT, old2);
  1325.     if (pid == -1) {
  1326.         perror("Try again later");
  1327.         code = -1;
  1328.     }
  1329.     else {
  1330.         code = 0;
  1331.     }
  1332.     return (0);
  1333. }
  1334.  
  1335. /*
  1336.  * Send new user information (re-login)
  1337.  */
  1338. user(argc, argv)
  1339.     int argc;
  1340.     char **argv;
  1341. {
  1342.     char acct[80], *getpass();
  1343.     int n, aflag = 0;
  1344.  
  1345.     if (argc < 2) {
  1346.         (void) strcat(line, " ");
  1347.         printf("(username) ");
  1348.         (void) gets(&line[strlen(line)]);
  1349.         makeargv();
  1350.         argc = margc;
  1351.         argv = margv;
  1352.     }
  1353.     if (argc > 4) {
  1354.         printf("usage: %s username [password] [account]\n", argv[0]);
  1355.         code = -1;
  1356.         return (0);
  1357.     }
  1358.     n = command("USER %s", argv[1]);
  1359.     if (n == CONTINUE) {
  1360.         if (argc < 3 )
  1361.             argv[2] = getpass("Password: "), argc++;
  1362.         n = command("PASS %s", argv[2]);
  1363.     }
  1364.     if (n == CONTINUE) {
  1365.         if (argc < 4) {
  1366.             printf("Account: "); (void) fflush(stdout);
  1367.             (void) fgets(acct, sizeof(acct) - 1, stdin);
  1368.             acct[strlen(acct) - 1] = '\0';
  1369.             argv[3] = acct; argc++;
  1370.         }
  1371.         n = command("ACCT %s", argv[3]);
  1372.         aflag++;
  1373.     }
  1374.     if (n != COMPLETE) {
  1375.         fprintf(stdout, "Login failed.\n");
  1376.         return (0);
  1377.     }
  1378.     if (!aflag && argc == 4) {
  1379.         (void) command("ACCT %s", argv[3]);
  1380.     }
  1381.     return (1);
  1382. }
  1383.  
  1384. /*
  1385.  * Print working directory.
  1386.  */
  1387. /*VARARGS*/
  1388. pwd()
  1389. {
  1390.     int oldverbose = verbose;
  1391.  
  1392.     /*
  1393.      * If we aren't verbose, this doesn't do anything!
  1394.      */
  1395.     verbose = 1;
  1396.     if (command("PWD") == ERROR && code == 500) {
  1397.         printf("PWD command not recognized, trying XPWD\n");
  1398.         (void) command("XPWD");
  1399.     }
  1400.     verbose = oldverbose;
  1401. }
  1402.  
  1403. /*
  1404.  * Make a directory.
  1405.  */
  1406. makedir(argc, argv)
  1407.     char *argv[];
  1408. {
  1409.  
  1410.     if (argc < 2) {
  1411.         (void) strcat(line, " ");
  1412.         printf("(directory-name) ");
  1413.         (void) gets(&line[strlen(line)]);
  1414.         makeargv();
  1415.         argc = margc;
  1416.         argv = margv;
  1417.     }
  1418.     if (argc < 2) {
  1419.         printf("usage: %s directory-name\n", argv[0]);
  1420.         code = -1;
  1421.         return;
  1422.     }
  1423.     if (command("MKD %s", argv[1]) == ERROR && code == 500) {
  1424.         if (verbose)
  1425.             printf("MKD command not recognized, trying XMKD\n");
  1426.         (void) command("XMKD %s", argv[1]);
  1427.     }
  1428. }
  1429.  
  1430. /*
  1431.  * Remove a directory.
  1432.  */
  1433. removedir(argc, argv)
  1434.     char *argv[];
  1435. {
  1436.  
  1437.     if (argc < 2) {
  1438.         (void) strcat(line, " ");
  1439.         printf("(directory-name) ");
  1440.         (void) gets(&line[strlen(line)]);
  1441.         makeargv();
  1442.         argc = margc;
  1443.         argv = margv;
  1444.     }
  1445.     if (argc < 2) {
  1446.         printf("usage: %s directory-name\n", argv[0]);
  1447.         code = -1;
  1448.         return;
  1449.     }
  1450.     if (command("RMD %s", argv[1]) == ERROR && code == 500) {
  1451.         if (verbose)
  1452.             printf("RMD command not recognized, trying XRMD\n");
  1453.         (void) command("XRMD %s", argv[1]);
  1454.     }
  1455. }
  1456.  
  1457. /*
  1458.  * Send a line, verbatim, to the remote machine.
  1459.  */
  1460. quote(argc, argv)
  1461.     char *argv[];
  1462. {
  1463.     int i;
  1464.     char buf[BUFSIZ];
  1465.  
  1466.     if (argc < 2) {
  1467.         (void) strcat(line, " ");
  1468.         printf("(command line to send) ");
  1469.         (void) gets(&line[strlen(line)]);
  1470.         makeargv();
  1471.         argc = margc;
  1472.         argv = margv;
  1473.     }
  1474.     if (argc < 2) {
  1475.         printf("usage: %s line-to-send\n", argv[0]);
  1476.         code = -1;
  1477.         return;
  1478.     }
  1479.     (void) strcpy(buf, argv[1]);
  1480.     for (i = 2; i < argc; i++) {
  1481.         (void) strcat(buf, " ");
  1482.         (void) strcat(buf, argv[i]);
  1483.     }
  1484.     if (command(buf) == PRELIM) {
  1485.         while (getreply(0) == PRELIM);
  1486.     }
  1487. }
  1488.  
  1489. /*
  1490.  * Send a SITE command to the remote machine.  The line
  1491.  * is sent almost verbatim to the remote machine, the
  1492.  * first argument is changed to SITE.
  1493.  */
  1494.  
  1495. site(argc, argv)
  1496.     char *argv[];
  1497. {
  1498.     int i;
  1499.     char buf[BUFSIZ];
  1500.  
  1501.     if (argc < 2) {
  1502.         (void) strcat(line, " ");
  1503.         printf("(arguments to SITE command) ");
  1504.         (void) gets(&line[strlen(line)]);
  1505.         makeargv();
  1506.         argc = margc;
  1507.         argv = margv;
  1508.     }
  1509.     if (argc < 2) {
  1510.         printf("usage: %s line-to-send\n", argv[0]);
  1511.         code = -1;
  1512.         return;
  1513.     }
  1514.     (void) strcpy(buf, "SITE ");
  1515.     (void) strcat(buf, argv[1]);
  1516.     for (i = 2; i < argc; i++) {
  1517.         (void) strcat(buf, " ");
  1518.         (void) strcat(buf, argv[i]);
  1519.     }
  1520.     if (command(buf) == PRELIM) {
  1521.         while (getreply(0) == PRELIM);
  1522.     }
  1523. }
  1524.  
  1525. do_chmod(argc, argv)
  1526.     char *argv[];
  1527. {
  1528.     if (argc == 2) {
  1529.         printf("usage: %s mode file-name\n", argv[0]);
  1530.         code = -1;
  1531.         return;
  1532.     }
  1533.     if (argc < 3) {
  1534.         (void) strcat(line, " ");
  1535.         printf("(mode and file-name) ");
  1536.         (void) gets(&line[strlen(line)]);
  1537.         makeargv();
  1538.         argc = margc;
  1539.         argv = margv;
  1540.     }
  1541.     if (argc != 3) {
  1542.         printf("usage: %s mode file-name\n", argv[0]);
  1543.         code = -1;
  1544.         return;
  1545.     }
  1546.     (void)command("SITE CHMOD %s %s", argv[1], argv[2]);
  1547. }
  1548.  
  1549. do_umask(argc, argv)
  1550.     char *argv[];
  1551. {
  1552.     int oldverbose = verbose;
  1553.  
  1554.     verbose = 1;
  1555.     (void) command(argc == 1 ? "SITE UMASK" : "SITE UMASK %s", argv[1]);
  1556.     verbose = oldverbose;
  1557. }
  1558.  
  1559. idle(argc, argv)
  1560.     char *argv[];
  1561. {
  1562.     int oldverbose = verbose;
  1563.  
  1564.     verbose = 1;
  1565.     (void) command(argc == 1 ? "SITE IDLE" : "SITE IDLE %s", argv[1]);
  1566.     verbose = oldverbose;
  1567. }
  1568.  
  1569. /*
  1570.  * Ask the other side for help.
  1571.  */
  1572. rmthelp(argc, argv)
  1573.     char *argv[];
  1574. {
  1575.     int oldverbose = verbose;
  1576.  
  1577.     verbose = 1;
  1578.     (void) command(argc == 1 ? "HELP" : "HELP %s", argv[1]);
  1579.     verbose = oldverbose;
  1580. }
  1581.  
  1582. /*
  1583.  * Terminate session and exit.
  1584.  */
  1585. /*VARARGS*/
  1586. quit()
  1587. {
  1588.  
  1589.     if (connected)
  1590.         disconnect();
  1591.     pswitch(1);
  1592.     if (connected) {
  1593.         disconnect();
  1594.     }
  1595.     exit(0);
  1596. }
  1597.  
  1598. /*
  1599.  * Terminate session, but don't exit.
  1600.  */
  1601. disconnect()
  1602. {
  1603.     extern FILE *cout;
  1604.     extern int data;
  1605.  
  1606.     if (!connected)
  1607.         return;
  1608.     (void) command("QUIT");
  1609.     if (cout) {
  1610.         (void) fclose(cout);
  1611.     }
  1612.     cout = NULL;
  1613.     connected = 0;
  1614.     data = -1;
  1615.     if (!proxy) {
  1616.         macnum = 0;
  1617.     }
  1618. }
  1619.  
  1620. confirm(cmd, file)
  1621.     char *cmd, *file;
  1622. {
  1623.     char line[BUFSIZ];
  1624.  
  1625.     if (!interactive)
  1626.         return (1);
  1627.     printf("%s %s? ", cmd, file);
  1628.     (void) fflush(stdout);
  1629.     (void) gets(line);
  1630.     return (*line != 'n' && *line != 'N');
  1631. }
  1632.  
  1633. fatal(msg)
  1634.     char *msg;
  1635. {
  1636.  
  1637.     fprintf(stderr, "ftp: %s\n", msg);
  1638.     exit(1);
  1639. }
  1640.  
  1641. /*
  1642.  * Glob a local file name specification with
  1643.  * the expectation of a single return value.
  1644.  * Can't control multiple values being expanded
  1645.  * from the expression, we return only the first.
  1646.  */
  1647. globulize(cpp)
  1648.     char **cpp;
  1649. {
  1650.     char **globbed;
  1651.  
  1652.     if (!doglob)
  1653.         return (1);
  1654.     globbed = glob(*cpp);
  1655.     if (globerr != NULL) {
  1656.         printf("%s: %s\n", *cpp, globerr);
  1657.         if (globbed) {
  1658.             blkfree(globbed);
  1659.             free((char *)globbed);
  1660.         }
  1661.         return (0);
  1662.     }
  1663.     if (globbed) {
  1664.         *cpp = *globbed++;
  1665.         /* don't waste too much memory */
  1666.         if (*globbed) {
  1667.             blkfree(globbed);
  1668.             free((char *)globbed);
  1669.         }
  1670.     }
  1671.     return (1);
  1672. }
  1673.  
  1674. account(argc,argv)
  1675.     int argc;
  1676.     char **argv;
  1677. {
  1678.     char acct[50], *getpass(), *ap;
  1679.  
  1680.     if (argc > 1) {
  1681.         ++argv;
  1682.         --argc;
  1683.         (void) strncpy(acct,*argv,49);
  1684.         acct[49] = '\0';
  1685.         while (argc > 1) {
  1686.             --argc;
  1687.             ++argv;
  1688.             (void) strncat(acct,*argv, 49-strlen(acct));
  1689.         }
  1690.         ap = acct;
  1691.     }
  1692.     else {
  1693.         ap = getpass("Account:");
  1694.     }
  1695.     (void) command("ACCT %s", ap);
  1696. }
  1697.  
  1698. jmp_buf abortprox;
  1699.  
  1700. void
  1701. proxabort()
  1702. {
  1703.     extern int proxy;
  1704.  
  1705.     if (!proxy) {
  1706.         pswitch(1);
  1707.     }
  1708.     if (connected) {
  1709.         proxflag = 1;
  1710.     }
  1711.     else {
  1712.         proxflag = 0;
  1713.     }
  1714.     pswitch(0);
  1715.     longjmp(abortprox,1);
  1716. }
  1717.  
  1718. doproxy(argc,argv)
  1719.     int argc;
  1720.     char *argv[];
  1721. {
  1722.     extern struct cmd cmdtab[];
  1723.     extern jmp_buf abortprox;
  1724.     register struct cmd *c;
  1725.     struct cmd *getcmd();
  1726.     sig_t oldintr;
  1727.     void proxabort();
  1728.  
  1729.     if (argc < 2) {
  1730.         (void) strcat(line, " ");
  1731.         printf("(command) ");
  1732.         (void) gets(&line[strlen(line)]);
  1733.         makeargv();
  1734.         argc = margc;
  1735.         argv = margv;
  1736.     }
  1737.     if (argc < 2) {
  1738.         printf("usage:%s command\n", argv[0]);
  1739.         code = -1;
  1740.         return;
  1741.     }
  1742.     c = getcmd(argv[1]);
  1743.     if (c == (struct cmd *) -1) {
  1744.         printf("?Ambiguous command\n");
  1745.         (void) fflush(stdout);
  1746.         code = -1;
  1747.         return;
  1748.     }
  1749.     if (c == 0) {
  1750.         printf("?Invalid command\n");
  1751.         (void) fflush(stdout);
  1752.         code = -1;
  1753.         return;
  1754.     }
  1755.     if (!c->c_proxy) {
  1756.         printf("?Invalid proxy command\n");
  1757.         (void) fflush(stdout);
  1758.         code = -1;
  1759.         return;
  1760.     }
  1761.     if (setjmp(abortprox)) {
  1762.         code = -1;
  1763.         return;
  1764.     }
  1765.     oldintr = signal(SIGINT, proxabort);
  1766.     pswitch(1);
  1767.     if (c->c_conn && !connected) {
  1768.         printf("Not connected\n");
  1769.         (void) fflush(stdout);
  1770.         pswitch(0);
  1771.         (void) signal(SIGINT, oldintr);
  1772.         code = -1;
  1773.         return;
  1774.     }
  1775.     (*c->c_handler)(argc-1, argv+1);
  1776.     if (connected) {
  1777.         proxflag = 1;
  1778.     }
  1779.     else {
  1780.         proxflag = 0;
  1781.     }
  1782.     pswitch(0);
  1783.     (void) signal(SIGINT, oldintr);
  1784. }
  1785.  
  1786. setcase()
  1787. {
  1788.     mcase = !mcase;
  1789.     printf("Case mapping %s.\n", onoff(mcase));
  1790.     code = mcase;
  1791. }
  1792.  
  1793. setcr()
  1794. {
  1795.     crflag = !crflag;
  1796.     printf("Carriage Return stripping %s.\n", onoff(crflag));
  1797.     code = crflag;
  1798. }
  1799.  
  1800. setntrans(argc,argv)
  1801.     int argc;
  1802.     char *argv[];
  1803. {
  1804.     if (argc == 1) {
  1805.         ntflag = 0;
  1806.         printf("Ntrans off.\n");
  1807.         code = ntflag;
  1808.         return;
  1809.     }
  1810.     ntflag++;
  1811.     code = ntflag;
  1812.     (void) strncpy(ntin, argv[1], 16);
  1813.     ntin[16] = '\0';
  1814.     if (argc == 2) {
  1815.         ntout[0] = '\0';
  1816.         return;
  1817.     }
  1818.     (void) strncpy(ntout, argv[2], 16);
  1819.     ntout[16] = '\0';
  1820. }
  1821.  
  1822. char *
  1823. dotrans(name)
  1824.     char *name;
  1825. {
  1826.     static char new[MAXPATHLEN];
  1827.     char *cp1, *cp2 = new;
  1828.     register int i, ostop, found;
  1829.  
  1830.     for (ostop = 0; *(ntout + ostop) && ostop < 16; ostop++);
  1831.     for (cp1 = name; *cp1; cp1++) {
  1832.         found = 0;
  1833.         for (i = 0; *(ntin + i) && i < 16; i++) {
  1834.             if (*cp1 == *(ntin + i)) {
  1835.                 found++;
  1836.                 if (i < ostop) {
  1837.                     *cp2++ = *(ntout + i);
  1838.                 }
  1839.                 break;
  1840.             }
  1841.         }
  1842.         if (!found) {
  1843.             *cp2++ = *cp1;
  1844.         }
  1845.     }
  1846.     *cp2 = '\0';
  1847.     return(new);
  1848. }
  1849.  
  1850. setnmap(argc, argv)
  1851.     int argc;
  1852.     char *argv[];
  1853. {
  1854.     char *cp;
  1855.  
  1856.     if (argc == 1) {
  1857.         mapflag = 0;
  1858.         printf("Nmap off.\n");
  1859.         code = mapflag;
  1860.         return;
  1861.     }
  1862.     if (argc < 3) {
  1863.         (void) strcat(line, " ");
  1864.         printf("(mapout) ");
  1865.         (void) gets(&line[strlen(line)]);
  1866.         makeargv();
  1867.         argc = margc;
  1868.         argv = margv;
  1869.     }
  1870.     if (argc < 3) {
  1871.         printf("Usage: %s [mapin mapout]\n",argv[0]);
  1872.         code = -1;
  1873.         return;
  1874.     }
  1875.     mapflag = 1;
  1876.     code = 1;
  1877.     cp = index(altarg, ' ');
  1878.     if (proxy) {
  1879.         while(*++cp == ' ');
  1880.         altarg = cp;
  1881.         cp = index(altarg, ' ');
  1882.     }
  1883.     *cp = '\0';
  1884.     (void) strncpy(mapin, altarg, MAXPATHLEN - 1);
  1885.     while (*++cp == ' ');
  1886.     (void) strncpy(mapout, cp, MAXPATHLEN - 1);
  1887. }
  1888.  
  1889. char *
  1890. domap(name)
  1891.     char *name;
  1892. {
  1893.     static char new[MAXPATHLEN];
  1894.     register char *cp1 = name, *cp2 = mapin;
  1895.     char *tp[9], *te[9];
  1896.     int i, toks[9], toknum = 0, match = 1;
  1897.  
  1898.     for (i=0; i < 9; ++i) {
  1899.         toks[i] = 0;
  1900.     }
  1901.     while (match && *cp1 && *cp2) {
  1902.         switch (*cp2) {
  1903.             case '\\':
  1904.                 if (*++cp2 != *cp1) {
  1905.                     match = 0;
  1906.                 }
  1907.                 break;
  1908.             case '$':
  1909.                 if (*(cp2+1) >= '1' && (*cp2+1) <= '9') {
  1910.                     if (*cp1 != *(++cp2+1)) {
  1911.                         toks[toknum = *cp2 - '1']++;
  1912.                         tp[toknum] = cp1;
  1913.                         while (*++cp1 && *(cp2+1)
  1914.                             != *cp1);
  1915.                         te[toknum] = cp1;
  1916.                     }
  1917.                     cp2++;
  1918.                     break;
  1919.                 }
  1920.                 /* FALLTHROUGH */
  1921.             default:
  1922.                 if (*cp2 != *cp1) {
  1923.                     match = 0;
  1924.                 }
  1925.                 break;
  1926.         }
  1927.         if (match && *cp1) {
  1928.             cp1++;
  1929.         }
  1930.         if (match && *cp2) {
  1931.             cp2++;
  1932.         }
  1933.     }
  1934.     if (!match && *cp1) /* last token mismatch */
  1935.     {
  1936.         toks[toknum] = 0;
  1937.     }
  1938.     cp1 = new;
  1939.     *cp1 = '\0';
  1940.     cp2 = mapout;
  1941.     while (*cp2) {
  1942.         match = 0;
  1943.         switch (*cp2) {
  1944.             case '\\':
  1945.                 if (*(cp2 + 1)) {
  1946.                     *cp1++ = *++cp2;
  1947.                 }
  1948.                 break;
  1949.             case '[':
  1950. LOOP:
  1951.                 if (*++cp2 == '$' && isdigit(*(cp2+1))) { 
  1952.                     if (*++cp2 == '0') {
  1953.                         char *cp3 = name;
  1954.  
  1955.                         while (*cp3) {
  1956.                             *cp1++ = *cp3++;
  1957.                         }
  1958.                         match = 1;
  1959.                     }
  1960.                     else if (toks[toknum = *cp2 - '1']) {
  1961.                         char *cp3 = tp[toknum];
  1962.  
  1963.                         while (cp3 != te[toknum]) {
  1964.                             *cp1++ = *cp3++;
  1965.                         }
  1966.                         match = 1;
  1967.                     }
  1968.                 }
  1969.                 else {
  1970.                     while (*cp2 && *cp2 != ',' && 
  1971.                         *cp2 != ']') {
  1972.                         if (*cp2 == '\\') {
  1973.                             cp2++;
  1974.                         }
  1975.                         else if (*cp2 == '$' &&
  1976.                                    isdigit(*(cp2+1))) {
  1977.                             if (*++cp2 == '0') {
  1978.                                char *cp3 = name;
  1979.  
  1980.                                while (*cp3) {
  1981.                                 *cp1++ = *cp3++;
  1982.                                }
  1983.                             }
  1984.                             else if (toks[toknum =
  1985.                                 *cp2 - '1']) {
  1986.                                char *cp3=tp[toknum];
  1987.  
  1988.                                while (cp3 !=
  1989.                                   te[toknum]) {
  1990.                                 *cp1++ = *cp3++;
  1991.                                }
  1992.                             }
  1993.                         }
  1994.                         else if (*cp2) {
  1995.                             *cp1++ = *cp2++;
  1996.                         }
  1997.                     }
  1998.                     if (!*cp2) {
  1999.                         printf("nmap: unbalanced brackets\n");
  2000.                         return(name);
  2001.                     }
  2002.                     match = 1;
  2003.                     cp2--;
  2004.                 }
  2005.                 if (match) {
  2006.                     while (*++cp2 && *cp2 != ']') {
  2007.                           if (*cp2 == '\\' && *(cp2 + 1)) {
  2008.                             cp2++;
  2009.                           }
  2010.                     }
  2011.                     if (!*cp2) {
  2012.                         printf("nmap: unbalanced brackets\n");
  2013.                         return(name);
  2014.                     }
  2015.                     break;
  2016.                 }
  2017.                 switch (*++cp2) {
  2018.                     case ',':
  2019.                         goto LOOP;
  2020.                     case ']':
  2021.                         break;
  2022.                     default:
  2023.                         cp2--;
  2024.                         goto LOOP;
  2025.                 }
  2026.                 break;
  2027.             case '$':
  2028.                 if (isdigit(*(cp2 + 1))) {
  2029.                     if (*++cp2 == '0') {
  2030.                         char *cp3 = name;
  2031.  
  2032.                         while (*cp3) {
  2033.                             *cp1++ = *cp3++;
  2034.                         }
  2035.                     }
  2036.                     else if (toks[toknum = *cp2 - '1']) {
  2037.                         char *cp3 = tp[toknum];
  2038.  
  2039.                         while (cp3 != te[toknum]) {
  2040.                             *cp1++ = *cp3++;
  2041.                         }
  2042.                     }
  2043.                     break;
  2044.                 }
  2045.                 /* intentional drop through */
  2046.             default:
  2047.                 *cp1++ = *cp2;
  2048.                 break;
  2049.         }
  2050.         cp2++;
  2051.     }
  2052.     *cp1 = '\0';
  2053.     if (!*new) {
  2054.         return(name);
  2055.     }
  2056.     return(new);
  2057. }
  2058.  
  2059. setsunique()
  2060. {
  2061.     sunique = !sunique;
  2062.     printf("Store unique %s.\n", onoff(sunique));
  2063.     code = sunique;
  2064. }
  2065.  
  2066. setrunique()
  2067. {
  2068.     runique = !runique;
  2069.     printf("Receive unique %s.\n", onoff(runique));
  2070.     code = runique;
  2071. }
  2072.  
  2073. /* change directory to perent directory */
  2074. cdup()
  2075. {
  2076.     if (command("CDUP") == ERROR && code == 500) {
  2077.         if (verbose)
  2078.             printf("CDUP command not recognized, trying XCUP\n");
  2079.         (void) command("XCUP");
  2080.     }
  2081. }
  2082.  
  2083. /* restart transfer at specific point */
  2084. restart(argc, argv)
  2085.     int argc;
  2086.     char *argv[];
  2087. {
  2088.     extern long atol();
  2089.     if (argc != 2)
  2090.         printf("restart: offset not specified\n");
  2091.     else {
  2092.         restart_point = atol(argv[1]);
  2093.         printf("restarting at %ld. %s\n", restart_point,
  2094.             "execute get, put or append to initiate transfer");
  2095.     }
  2096. }
  2097.  
  2098. /* show remote system type */
  2099. syst()
  2100. {
  2101.     (void) command("SYST");
  2102. }
  2103.  
  2104. macdef(argc, argv)
  2105.     int argc;
  2106.     char *argv[];
  2107. {
  2108.     char *tmp;
  2109.     int c;
  2110.  
  2111.     if (macnum == 16) {
  2112.         printf("Limit of 16 macros have already been defined\n");
  2113.         code = -1;
  2114.         return;
  2115.     }
  2116.     if (argc < 2) {
  2117.         (void) strcat(line, " ");
  2118.         printf("(macro name) ");
  2119.         (void) gets(&line[strlen(line)]);
  2120.         makeargv();
  2121.         argc = margc;
  2122.         argv = margv;
  2123.     }
  2124.     if (argc != 2) {
  2125.         printf("Usage: %s macro_name\n",argv[0]);
  2126.         code = -1;
  2127.         return;
  2128.     }
  2129.     if (interactive) {
  2130.         printf("Enter macro line by line, terminating it with a null line\n");
  2131.     }
  2132.     (void) strncpy(macros[macnum].mac_name, argv[1], 8);
  2133.     if (macnum == 0) {
  2134.         macros[macnum].mac_start = macbuf;
  2135.     }
  2136.     else {
  2137.         macros[macnum].mac_start = macros[macnum - 1].mac_end + 1;
  2138.     }
  2139.     tmp = macros[macnum].mac_start;
  2140.     while (tmp != macbuf+4096) {
  2141.         if ((c = getchar()) == EOF) {
  2142.             printf("macdef:end of file encountered\n");
  2143.             code = -1;
  2144.             return;
  2145.         }
  2146.         if ((*tmp = c) == '\n') {
  2147.             if (tmp == macros[macnum].mac_start) {
  2148.                 macros[macnum++].mac_end = tmp;
  2149.                 code = 0;
  2150.                 return;
  2151.             }
  2152.             if (*(tmp-1) == '\0') {
  2153.                 macros[macnum++].mac_end = tmp - 1;
  2154.                 code = 0;
  2155.                 return;
  2156.             }
  2157.             *tmp = '\0';
  2158.         }
  2159.         tmp++;
  2160.     }
  2161.     while (1) {
  2162.         while ((c = getchar()) != '\n' && c != EOF)
  2163.             /* LOOP */;
  2164.         if (c == EOF || getchar() == '\n') {
  2165.             printf("Macro not defined - 4k buffer exceeded\n");
  2166.             code = -1;
  2167.             return;
  2168.         }
  2169.     }
  2170. }
  2171.  
  2172. /*
  2173.  * get size of file on remote machine
  2174.  */
  2175. sizecmd(argc, argv)
  2176.     char *argv[];
  2177. {
  2178.  
  2179.     if (argc < 2) {
  2180.         (void) strcat(line, " ");
  2181.         printf("(filename) ");
  2182.         (void) gets(&line[strlen(line)]);
  2183.         makeargv();
  2184.         argc = margc;
  2185.         argv = margv;
  2186.     }
  2187.     if (argc < 2) {
  2188.         printf("usage:%s filename\n", argv[0]);
  2189.         code = -1;
  2190.         return;
  2191.     }
  2192.     (void) command("SIZE %s", argv[1]);
  2193. }
  2194.  
  2195. /*
  2196.  * get last modification time of file on remote machine
  2197.  */
  2198. modtime(argc, argv)
  2199.     char *argv[];
  2200. {
  2201.     int overbose;
  2202.  
  2203.     if (argc < 2) {
  2204.         (void) strcat(line, " ");
  2205.         printf("(filename) ");
  2206.         (void) gets(&line[strlen(line)]);
  2207.         makeargv();
  2208.         argc = margc;
  2209.         argv = margv;
  2210.     }
  2211.     if (argc < 2) {
  2212.         printf("usage:%s filename\n", argv[0]);
  2213.         code = -1;
  2214.         return;
  2215.     }
  2216.     overbose = verbose;
  2217.     if (debug == 0)
  2218.         verbose = -1;
  2219.     if (command("MDTM %s", argv[1]) == COMPLETE) {
  2220.         int yy, mo, day, hour, min, sec;
  2221.         sscanf(reply_string, "%*s %04d%02d%02d%02d%02d%02d", &yy, &mo,
  2222.             &day, &hour, &min, &sec);
  2223.         /* might want to print this in local time */
  2224.         printf("%s\t%02d/%02d/%04d %02d:%02d:%02d GMT\n", argv[1],
  2225.             mo, day, yy, hour, min, sec);
  2226.     } else
  2227.         printf("%s\n", reply_string);
  2228.     verbose = overbose;
  2229. }
  2230.  
  2231. /*
  2232.  * show status on reomte machine
  2233.  */
  2234. rmtstatus(argc, argv)
  2235.     char *argv[];
  2236. {
  2237.     (void) command(argc > 1 ? "STAT %s" : "STAT" , argv[1]);
  2238. }
  2239.  
  2240. /*
  2241.  * get file if modtime is more recent than current file
  2242.  */
  2243. newer(argc, argv)
  2244.     char *argv[];
  2245. {
  2246.     if (getit(argc, argv, -1, "w"))
  2247.         printf("Local file \"%s\" is newer than remote file \"%s\"\n",
  2248.             argv[1], argv[2]);
  2249. }
  2250.